home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1997 December
/
MACPOWER-1997-12.ISO.7z
/
MACPOWER-1997-12.ISO
/
AMUG
/
PROGRAMMING
/
Raven 1.2.sit
/
Raven 1.2
/
Source
/
Foundation
/
Common
/
ZInvariant.h
< prev
next >
Wrap
Text File
|
1997-06-18
|
6KB
|
199 lines
/*
* File: ZInvariant.h
* Summary: Mixin for objects that use PRECONDITION and POSTCONDITION macros.
* Written by: Jesse Jones
*
* Abstract: According to the design by contract design methodology (see _Object
* Oriented Software Construction_) clients of an object promise to call
* an objects methods with correct arguments and the object promises to
* do the right thing when given correct arguments. Since we're trying
* to write robust software we'll check to make sure each party lives up
* to the contract.
*
* To do this check we use two macros: PRECONDITION and POSTCONDITION.
* PRECONDITION is used to check a methods arguments and POSTCONDITION
* is used to check that the method did what it's supposed to. Since
* objects have state these macros also check to see that the object's
* state is still consistent. They do this by calling the Invariant
* method. Subclasses should override this and add ASSERTs to verify
* that the object is still OK.
*
* Note that these checks should only be done for public methods: while
* inside a public method the object may temporarily enter an invalid
* state.
*
* In Raven 1.0 the macros looked like this:
* #define PRECONDITION(x) this->Invariant(); ASSERT(x);
* #define POSTCONDITION(x) this->Invariant(); ASSERT(x);
* This was nice and simple, but caused problems when a protected
* method called a public functions. If the object happened to be
* in an invalid state the Invariant method would fire. When this
* happened the easiest fix was simply to replace the PRECONDITION
* and POSTCONDITION checks with an ASSERT. This was obviously not
* a good solution.
*
* Raven 1.1 uses a more sophisticated approach that, unfortunately,
* requires objects to descend from MInvariant if they wish to use
* PRECONDITION and POSTCONDITION. The new macros look like this:
* #define PRECONDITION(x) ASSERT(x); ¥
* const MInvariant* _object = dynamic_cast<const MInvariant*>(this); ¥
* ASSERT(_object != nil); ¥
* ZCheckInvariant _check(_object)
* #define POSTCONDITION(x) ASSERT(x)
* ZCheckInvariant is a stack based class that increments an MInvariants
* nesting level and calls the Invariant method if the nesting level is
* one. By doing this the Invariant function is only called at the start
* and end of the original public method. The 'this' pointer is cast to
* an MInvariant* to allow PRECONDITION to be used inside a mixin class
* (which, of course, requires that the concrete class descend from MInvariant).
*
* Classes: ZCheckInvariant - PRECONDITION creates one of these to ensure that
* the Invariant method is only called at the entry
* and exit of a function.
* TDisableInvariant - Can be used to disable invariant checks within a block.
* MInvariant - Mixin allowing PRECONDITION and POSTCONDITION macros
* to be used.
*
* Copyright ゥ 1997 Jesse Jones.
* For conditions of distribution and use, see copyright notice in ZTypes.h
*
* Change History (most recent first):
*
* <4> 6/14/97 JDJ Provided an implementation of pure virtual Invariant.
* <3> 5/17/97 JDJ Updated Abstract.
* <2> 5/17/97 JDJ ZCheckInvariant ctor ASSERTs that object is non-nil.
* <1> 4/12/97 JDJ Created.
*/
#pragma once
//-----------------------------------
// Forward References
//
class MInvariant;
class ZCheckInvariant;
// ===================================================================================
// class ZCheckInvariant
// ===================================================================================
#if DEBUG
class ZCheckInvariant {
//-----------------------------------
// Initialization/Destruction
//
public:
~ZCheckInvariant();
// Calls Invariant if object's nesting is one and then decrements nesting.
ZCheckInvariant(const MInvariant* object);
// Increments mNesting and calls Invariant if it's one.
//-----------------------------------
// Member Data
//
protected:
const MInvariant* mObject;
};
#endif
// ===================================================================================
// class TDisableInvariant
// ===================================================================================
class TDisableInvariant {
//-----------------------------------
// Initialization/Destruction
//
public:
~TDisableInvariant();
// Decrements mNesting.
TDisableInvariant(const MInvariant* object);
// Increments mNesting (so Invariant won't be called).
//-----------------------------------
// Member Data
//
protected:
#if DEBUG
const MInvariant* mObject;
#endif
};
// ===================================================================================
// class MInvariant
// ===================================================================================
class MInvariant {
friend ZCheckInvariant;
friend TDisableInvariant;
//-----------------------------------
// Initialization/Destruction
//
public:
virtual ~MInvariant();
MInvariant();
//-----------------------------------
// API
//
protected:
virtual void Invariant() const = 0;
// Override and add ASSERTs to ensure your subclasses member data
// are still valid. Note that you should *always* call the
// Inherited Invariant.
//-----------------------------------
// Member Data
//
protected:
#if DEBUG
mutable long mNesting;
#endif
};
// ===================================================================================
// Inlines
// ===================================================================================
#if DEBUG
inline TDisableInvariant::~TDisableInvariant()
{
mObject->mNesting--;
}
inline TDisableInvariant::TDisableInvariant(const MInvariant* object)
{
mObject = object;
mObject->mNesting++;
}
#else
inline TDisableInvariant::~TDisableInvariant()
{
}
inline TDisableInvariant::TDisableInvariant(const MInvariant*)
{
}
inline MInvariant::~MInvariant()
{
}
inline MInvariant::MInvariant()
{
}
inline void MInvariant::Invariant() const
{
}
#endif // DEBUG